<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8"> <!-- 关键！强制使用UTF-8编码 -->
    <title>WebSocket 客户端</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        .container {
            display: flex;
            flex-direction: column;
            gap: 15px;
        }
        button {
            padding: 10px 15px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
        }
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        .status {
            padding: 10px;
            border-radius: 4px;
            background-color: #f0f0f0;
        }
        .connected { background-color: #d4edda; }
        .disconnected { background-color: #f8d7da; }
        textarea {
            width: 100%;
            height: 100px;
            padding: 10px;
            box-sizing: border-box;
        }

        /* 新增消息容器样式 */
        #messages-container {
            height: 300px;
            overflow-y: auto; /* 添加垂直滚动条 */
            border: 1px solid #ddd;
            border-radius: 4px;
            padding: 10px;
            margin-top: 10px;
            background-color: #fafafa;
        }

        .message-item {
            margin-bottom: 8px;
            padding: 8px;
            border-bottom: 1px solid #eee;
            font-family: monospace;
            font-size: 14px;
        }

        .message-timestamp {
            color: #888;
            font-size: 12px;
            margin-right: 10px;
        }
    </style>
</head>
<body>
<div class="container">
    <h1>WebSocket 客户端</h1>

    <!-- 连接控制区域 -->
    <div>
        <button id="connectBtn">建立连接</button>
        <button id="disconnectBtn" disabled>断开连接</button>
    </div>

    <!-- 连接状态显示 -->
    <div id="status" class="status disconnected">未连接</div>

    <!-- 消息发送区域 -->
    <div>
        <label for="messageType">消息类型：</label>
        <select id="messageType">
            <option value="C_TO_S_AUTH_ACTIVE">认证激活</option>
            <option value="C_TO_S_CUSTOM_MSG">自定义消息</option>
        </select>

        <div>
            <textarea id="messageInput" placeholder="输入JSON格式的消息内容"></textarea>
        </div>

        <button id="sendBtn" disabled>发送消息</button>
    </div>

    <!-- 消息接收区域 -->
    <div>
        <h3>接收到的消息：</h3>
        <div id="messages-container"> <!-- 修改为带滚动条的容器 -->
            <div id="messages"></div> <!-- 消息实际显示位置 -->
        </div>
    </div>
</div>

<script>
    // WebSocket 相关变量
    let ws = null;
    let heartTimeout = null;
    const serverUrl = "ws://192.168.1.15:8080/ws"; // todo 修改成对应ip

    // DOM 元素
    const connectBtn = document.getElementById('connectBtn');
    const disconnectBtn = document.getElementById('disconnectBtn');
    const sendBtn = document.getElementById('sendBtn');
    const statusDiv = document.getElementById('status');
    const messageInput = document.getElementById('messageInput');
    const messagesDiv = document.getElementById('messages');
    const messageTypeSelect = document.getElementById('messageType');
    const messagesContainer = document.getElementById('messages-container'); // 新增容器元素

    // 建立WebSocket连接
    connectBtn.addEventListener('click', () => {
        if (ws && ws.readyState !== WebSocket.CLOSED) {
            logMessage("连接已存在，无需重复创建");
            return;
        }

        ws = new WebSocket(serverUrl);
        updateStatus("connecting", "连接中...");
        disableButtons(true, true, true);

        // 连接成功回调
        ws.onopen = () => {
            logMessage("连接成功");
            updateStatus("connected", "已连接");
            disableButtons(true, false, false);

            // 自动发送认证消息
            const authMsg = {type: "C_TO_S_ACTIVATE_VERIFICATION", license: "2dp61y", macAddr: "eva123"};
            // const authMsg = {type: "C_TO_S_ACTIVATE_VERIFICATION", license: "2dp61y", macAddr: "17533221620491230442"};
            ws.send(JSON.stringify(authMsg));
            logMessage(`已发送认证消息: ${JSON.stringify(authMsg)}`);

            // 启动心跳检测
            resetHeartbeat();
        };

        // 接收消息回调
        ws.onmessage = (event) => {
            try {
                const data = JSON.parse(event.data);
                logMessage(`收到消息: ${JSON.stringify(data)}`);
                // 定位到最新消息位置
                messagesContainer.scrollTop = messagesContainer.scrollHeight;

                // 处理心跳消息
                if (data.type === "S_TO_C_HEART") {
                    resetHeartbeat();
                }
            } catch (e) {
                logMessage(`收到非JSON消息: ${event.data}`);
            }
        };

        // 错误处理
        ws.onerror = (error) => {
            logMessage(`连接错误: ${error.message || "未知错误"}`);
            updateStatus("error", "连接错误");
            clearHeartbeat();
            disableButtons(false, true, true);
        };

        // 连接关闭回调
        ws.onclose = () => {
            logMessage("连接已关闭");
            updateStatus("disconnected", "连接已断开");
            clearHeartbeat();
            disableButtons(false, true, true);
            // 定位到最新消息位置
            messagesContainer.scrollTop = messagesContainer.scrollHeight;
        };
    });

    // 断开连接
    disconnectBtn.addEventListener('click', () => {
        if (ws && ws.readyState === WebSocket.OPEN) {
            ws.close();
        }
    });

    // 发送自定义消息
    sendBtn.addEventListener('click', () => {
        if (!ws || ws.readyState !== WebSocket.OPEN) {
            logMessage("连接未建立，无法发送消息");
            return;
        }

        try {
            const messageType = messageTypeSelect.value;
            let messageContent = {};

            // 处理不同消息类型
            if (messageType === "C_TO_S_CUSTOM_MSG") {
                messageContent = JSON.parse(messageInput.value || "{}");
            }

            const message = {
                type: messageType,
                ...messageContent
            };

            ws.send(JSON.stringify(message));
            logMessage(`已发送消息: ${JSON.stringify(message)}`);
            messageInput.value = ""; // 清空输入框
        } catch (e) {
            logMessage(`消息格式错误: ${e.message}`);
            // 定位到最新消息位置
            messagesContainer.scrollTop = messagesContainer.scrollHeight;
        }
    });

    // 心跳机制
    function resetHeartbeat() {
        clearTimeout(heartTimeout);
        // 35秒未收到心跳视为断开（>30秒容错）
        heartTimeout = setTimeout(() => {
            logMessage("服务器心跳丢失，断开连接");
            if (ws && ws.readyState === WebSocket.OPEN) {
                ws.close();
            }
        }, 35000);
    }

    function clearHeartbeat() {
        clearTimeout(heartTimeout);
    }

    // 更新状态显示
    function updateStatus(status, text) {
        statusDiv.className = `status ${status}`;
        statusDiv.textContent = text;
    }

    // 按钮状态控制
    function disableButtons(connectDisabled, disconnectDisabled, sendDisabled) {
        connectBtn.disabled = connectDisabled;
        disconnectBtn.disabled = disconnectDisabled;
        sendBtn.disabled = sendDisabled;
    }

    // 日志记录（已修改）
    function logMessage(message) {
        const messageElement = document.createElement('div');
        messageElement.className = 'message-item';

        // 添加时间戳
        const timestamp = document.createElement('span');
        timestamp.className = 'message-timestamp';
        timestamp.textContent = `[${new Date().toLocaleTimeString()}]`;
        messageElement.appendChild(timestamp);

        // 添加消息内容
        const content = document.createElement('span');
        content.textContent = message;
        messageElement.appendChild(content);

        messagesDiv.appendChild(messageElement);

        // 自动滚动到最新消息位置
        // messagesContainer.scrollTop = messagesContainer.scrollHeight;
    }
</script>
</body>
</html>